import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { ComponentPropsType } from "../../pages/components/QuestionComponents";
import produce from "immer";
import { getNextSelectedId, insertNewComponent } from "./utils";
import cloneDeep from "lodash.clonedeep";
import { nanoid } from "nanoid";
import { arrayMove } from "@dnd-kit/sortable";

export type ComponentInfoType = {
  id: string;
  type: string;
  title: string;
  isHidden?: boolean;
  isLocked?: boolean;
  props: ComponentPropsType;
};

export type ComponentsStateType = {
  selectedId: string;
  componentList: Array<ComponentInfoType>;
  copiedComponent?: ComponentInfoType | null;
};

const INIT_STATE: ComponentsStateType = {
  selectedId: "",
  componentList: [],
  copiedComponent: null,
};

const componentsSlice = createSlice({
  name: "components",
  initialState: INIT_STATE,
  reducers: {
    // 重置组件
    resetComponent: (
      state: ComponentsStateType,
      action: PayloadAction<ComponentsStateType>
    ) => action.payload,

    // 修改选中组件
    changeSelectedId: produce(
      (draft: ComponentsStateType, action: PayloadAction<string>) => {
        draft.selectedId = action.payload;
      }
    ),

    // 新增组件
    addComponent: produce(
      (
        draft: ComponentsStateType,
        action: PayloadAction<ComponentInfoType>
      ) => {
        const { payload } = action;
        insertNewComponent(draft, payload);
      }
    ),

    // 修改组件属性
    changeComponentProps: produce(
      (
        draft: ComponentsStateType,
        action: PayloadAction<{ id: string; newProps: ComponentPropsType }>
      ) => {
        const { id, newProps } = action.payload;
        const currentComponent = draft.componentList.find((c) => c.id === id);
        if (currentComponent)
          currentComponent.props = {
            ...currentComponent.props,
            ...newProps,
          };
      }
    ),

    // 删除选中的组件
    removeSelectedComponent: produce((draft: ComponentsStateType) => {
      const { selectedId, componentList } = draft;
      if (!selectedId) return;
      const nextSelectedId = getNextSelectedId(selectedId, componentList);
      draft.selectedId = nextSelectedId;
      const index = componentList.findIndex((c) => c.id === selectedId);
      componentList.splice(index, 1);
    }),

    // 隐藏/显示组件
    changeComponentHidden: produce(
      (
        draft: ComponentsStateType,
        action: PayloadAction<{ id: string; isHidden: boolean }>
      ) => {
        const { componentList } = draft;
        const { id, isHidden } = action.payload;
        let nextSelectedId = "";
        if (isHidden) {
          nextSelectedId = getNextSelectedId(id, componentList);
        } else {
          nextSelectedId = id;
        }
        draft.selectedId = nextSelectedId;
        const currentComponent = componentList.find((c) => c.id === id);
        if (currentComponent) currentComponent.isHidden = isHidden;
      }
    ),

    // 锁定/解锁组件
    toggleComponentLocked: produce(
      (draft: ComponentsStateType, action: PayloadAction<{ id: string }>) => {
        const { componentList } = draft;
        const { id } = action.payload;
        const currentComponent = componentList.find((c) => c.id === id);
        if (currentComponent)
          currentComponent.isLocked = !currentComponent.isLocked;
      }
    ),

    // 拷贝当前选中组件
    copySelectedComponent: produce((draft: ComponentsStateType) => {
      const { selectedId, componentList } = draft;
      const currentComponent = componentList.find((c) => c.id === selectedId);
      if (currentComponent) draft.copiedComponent = cloneDeep(currentComponent);
    }),

    // 粘贴组件
    pasteCopiedComponent: produce((draft: ComponentsStateType) => {
      const { copiedComponent } = draft;
      if (!copiedComponent) return;
      copiedComponent.id = "temp--" + nanoid(6);
      insertNewComponent(draft, copiedComponent);
    }),

    // 选中上一个组件
    selectPrevComponent: produce((draft: ComponentsStateType) => {
      const { selectedId, componentList } = draft;
      const selectedIndex = componentList.findIndex((c) => c.id === selectedId);
      // 未选中和选中第一个无需继续
      if (selectedIndex <= 0) return;
      draft.selectedId = componentList[selectedIndex - 1].id;
    }),

    // 选中下一个组件
    selectNextComponent: produce((draft: ComponentsStateType) => {
      const { selectedId, componentList } = draft;
      const selectedIndex = componentList.findIndex((c) => c.id === selectedId);
      // 未选中和选中最后一个无需继续
      if (selectedIndex < 0 || selectedIndex === componentList.length - 1)
        return;
      draft.selectedId = componentList[selectedIndex + 1].id;
    }),

    // 修改组件标题
    changeComponentTitle: produce(
      (
        draft: ComponentsStateType,
        action: PayloadAction<{ id: string; title: string }>
      ) => {
        const { id, title } = action.payload;
        const currentComponent = draft.componentList.find((c) => c.id === id);
        if (currentComponent) currentComponent.title = title;
      }
    ),

    // 移动组件
    moveComponent: produce(
      (
        draft: ComponentsStateType,
        action: PayloadAction<{ oldIndex: number; newIndex: number }>
      ) => {
        const { componentList } = draft;
        const { oldIndex, newIndex } = action.payload;

        draft.componentList = arrayMove(componentList, oldIndex, newIndex);
      }
    ),
  },
});

export const {
  resetComponent,
  changeSelectedId,
  addComponent,
  changeComponentProps,
  removeSelectedComponent,
  changeComponentHidden,
  toggleComponentLocked,
  copySelectedComponent,
  pasteCopiedComponent,
  selectPrevComponent,
  selectNextComponent,
  changeComponentTitle,
  moveComponent,
} = componentsSlice.actions;

export default componentsSlice.reducer;
